package com.ltw.dreamer.report.service.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import com.ltw.dreamer.common.network.WebPageReader;
import com.ltw.dreamer.common.util.DateUtil;
import com.ltw.dreamer.common.util.VerticalTableUtil;
import com.ltw.dreamer.report.exception.FinancialReportException;
import com.ltw.dreamer.report.mapper.BalanceSheetMapper;
import com.ltw.dreamer.report.model.BalanceSheet;
import com.ltw.dreamer.report.model.BalanceSheetExample;
import com.ltw.dreamer.report.model.BalanceSheetExample.Criteria;
import com.ltw.dreamer.report.service.BalanceSheetService;
import com.ltw.dreamer.report.service.FinancialReportDefineService;
import com.ltw.dreamer.stock.model.Stock;

@Service
public class BalanceSheetServiceImpl implements BalanceSheetService {
	private static final Logger LOGGER = Logger.getLogger(BalanceSheetServiceImpl.class);
	
	public static final String PAGE_URI = "http://money.finance.sina.com.cn/corp/go.php/vFD_BalanceSheet/stockid/STOCK_CODE/ctrl/YEAR/displaytype/4.phtml";
	public static final String REPORT_NAME = "资产负债表";
	
	@Resource
	private WebPageReader reader = null;
	
	@Resource
	private FinancialReportDefineService financialReportDefineService = null;
	
	@Resource
	private BalanceSheetMapper mapper = null;
	
	public void updateBalanceSheet(Stock stock) {
		if (stock == null) throw new IllegalArgumentException("传入股票参数为空。");
		LOGGER.info("开始更新股票" + stock.getName() + "[" + stock.getCode() + "]资产负债信息>>>>");
		boolean noStop = true;
		int year = DateUtil.getCurrentYear();
		while (noStop) {
			try {
				noStop = updateBalanceSheet(stock, year--);
			} catch (FinancialReportException e) {
				LOGGER.warn(e.getLocalizedMessage());
			}
		}
		LOGGER.info("结束更新股票" + stock.getName() + "[" + stock.getCode() + "]资产负债信息>>>>");
	}

	private boolean updateBalanceSheet(Stock stock, int year) throws FinancialReportException {
		LOGGER.info("处理年份>>>>" + year);
		String pageUri = PAGE_URI.replaceFirst("STOCK_CODE", stock.getCode()).replaceFirst("YEAR", Integer.toString(year));
		// pageUri = "http://money.finance.sina.com.cn/corp/go.php/vFD_BalanceSheet/stockid/000001/ctrl/2011/displaytype/4.phtml";
		String content = reader.read(pageUri);
		if (content == null) {
			LOGGER.info("HTML文件读取错误，不再抓取本股票的数据：" + stock.getCode());
			return false;
		}
		Document doc = Jsoup.parse(content);
		Element element = doc.getElementById("BalanceSheetNewTable0");
		if (element == null) {
			LOGGER.info("HTML文件解析错误，不再抓取本股票的数据：" + stock.getCode());
			return false;
		}
		Elements allRows = element.getElementsByTag("tbody").get(0).getElementsByTag("tr");
		if (allRows == null || allRows.size() == 0) {
			LOGGER.info("资产负债表数据为空，股票代码：" + stock.getCode());
			return true; // 可能是数据临时存在问题，再往前爬一年看看
		}
		List<BalanceSheet> balanceSheetList = createBalanceSheetList(stock, allRows);
		
		for (BalanceSheet balanceSheet : balanceSheetList)
			insertBalanceSheet(balanceSheet);
		
		return true;
	}

	private List<BalanceSheet> createBalanceSheetList(Stock stock, Elements allRows) throws FinancialReportException {
		
		int index = findReportDateRowIndex(allRows);
		if (index == -1) {
			throw new FinancialReportException("资产负债表没有定义报表日期!");
		}
		
		List<BalanceSheet> balanceSheetList = new ArrayList<BalanceSheet>();
		List<Date> reportDateList = getReportDateList(allRows.get(index));
		boolean needStore = false;
		for (int i=0; i<reportDateList.size(); i++) {
			BalanceSheet balanceSheet = new BalanceSheet();
			balanceSheet.setCode(stock.getCode());
			balanceSheet.setCreatedDate(Calendar.getInstance().getTime());
			balanceSheet.setUpdatedDate(Calendar.getInstance().getTime());
			balanceSheet.setDate(reportDateList.get(i));
			
			if (!balanceSheetIsStoredAlready(balanceSheet)) needStore = true;
			
			balanceSheetList.add(balanceSheet);
		}
		if (!needStore) return new ArrayList<BalanceSheet>();
		
		index++;
		while (index < allRows.size())
			updateBalanceSheetList(balanceSheetList, allRows.get(index++));
		
		return balanceSheetList;
	}

	private int findReportDateRowIndex(Elements allRows) throws FinancialReportException {
		for (int i=0; i<allRows.size(); i++)
		{
			String rowdata = allRows.get(i).text();
			if (rowdata.indexOf("报表日期") != -1)
				return i;
		}
		return -1;
	}
	

	private List<Date> getReportDateList(Element element) throws FinancialReportException {
		String text = element.text();
		String[] items = text.split("\\s");
		List<Date> reportDateList = new ArrayList<Date>();
		
		if (!items[0].equals("报表日期"))
			throw new FinancialReportException("数据出现异常，报表日期配置有误，日期：" + text);

		try {
			for (int i=1; i<items.length; i++) {
				Date date = new SimpleDateFormat("yyyy-MM-dd").parse(items[i]);
				reportDateList.add(date);
			}
		} catch (ParseException e) {
			throw new FinancialReportException("资产负债表日期格式化时出现错误，日期：" + text);
		}
		
		return reportDateList;
	}
	private void updateBalanceSheetList(List<BalanceSheet> balanceSheetList, Element element) {
		String text = element.text();
		String[] items = text.split("\\s");
		if (!validateData(balanceSheetList, items)) {
			LOGGER.info("当前行的数据不符合规范要求，不做处理，text=" + text);
			return ;
		}
		
		String code = items[0].trim();
		if (code.length() == 0) return ;
		
		int index = financialReportDefineService.queryColumnIndex(REPORT_NAME, code);
		for (int i=0; i<balanceSheetList.size(); i++)
			VerticalTableUtil.invokePropertySetter(balanceSheetList.get(i), items[i+1], index);
	}

	private boolean validateData(List<BalanceSheet> balanceSheetList, String[] items) {
		if (items == null || balanceSheetList == null) return false;
		if (items.length != balanceSheetList.size() + 1) return false;
		boolean valid = false;
		for (int i=1; i<items.length; i++) {
			try {
				Double.parseDouble(items[i].replaceAll(",", ""));
				valid = true;
			} catch (NumberFormatException ex) {
				// LOGGER.info("当前行记录存在数据不规范, text=" + items[i]);
			}
		}
		return valid;
	}
	
	private void insertBalanceSheet(BalanceSheet balanceSheet) {
		mapper.insert(balanceSheet);
	}
	
	private boolean balanceSheetIsStoredAlready(BalanceSheet balanceSheet) {
		BalanceSheetExample example = new BalanceSheetExample();
		Criteria criteria = example.createCriteria();
		criteria.andCodeEqualTo(balanceSheet.getCode());
		criteria.andDateEqualTo(balanceSheet.getDate());
		List<BalanceSheet> balanceSheetList = mapper.selectByExample(example);
		if (balanceSheetList != null && balanceSheetList.size() != 0) {
			LOGGER.info("当前股票的资产负债表数据已经存在, 股票代码：" + balanceSheet.getCode() + ", 日期：" + balanceSheet.getDate());
			return true;
		}
		
		return false;
	}
}
